package structure

import (
	"gddgame.cc/galaxy/utils"
)

type LinkStruct struct {
}

// Link:多对多，无顺序，支持批量读取，不可重复
func (execute *Execute) GetLink(conn SafeConn, data Data, relation string) []BaseData {
	//lrange 0,-1
	c, _ := conn.Do("SMEMBERS", execute.Key+"/"+execute.GetDataType(data.GetDataType())+utils.ToString(data.GetId())+"/"+relation)
	if c == nil {
		return nil
	}
	rl := make([]BaseData, len(c.([]interface{})))
	for index, v := range c.([]interface{}) {
		r := BaseData{}
		_, _ = r.UnmarshalMsg(v.([]byte))
		rl[index] = r
	}
	return rl
}

func (execute *Execute) GetLinksWithRelation(conn SafeConn, t PublicDataType, relationIds map[string][]interface{}) []BaseData {
	all := []interface{}{}
	for relation, ids := range relationIds {
		keys := make([]interface{}, len(ids))
		for i, id := range ids {
			keys[i] = execute.Key + "/" + execute.GetDataType(t) + utils.ToString(id) + "/" + relation
		}
		all = append(all, keys...)
	}

	return execute.getLinks(conn, all)
}

func (execute *Execute) GetLinksWithIds(conn SafeConn, t PublicDataType, ids []interface{}, relations []string) []BaseData {
	keys := make([]interface{}, len(ids)*len(relations))
	for i, id := range ids {
		for j, relation := range relations {
			keys[i*j] = execute.Key + "/" + execute.GetDataType(t) + utils.ToString(id) + "/" + relation
		}
	}

	return execute.getLinks(conn, keys)
}

func (execute *Execute) getLinks(conn SafeConn, keys []interface{}) []BaseData {
	c, _ := conn.Do("SUNION", keys...)
	if c == nil {
		return nil
	}
	rl := make([]BaseData, len(c.([]interface{})))
	for index, v := range c.([]interface{}) {
		r := BaseData{}
		_, _ = r.UnmarshalMsg(v.([]byte))
		rl[index] = r
	}
	return rl
}

func (execute *Execute) AddLink(conn SafeConn, data1 Data, data2 Data, relation string) {
	key := execute.Key + "/" + execute.GetDataType(data1.GetDataType()) + utils.ToString(data1.GetId())
	//conn.Watch(key)
	_ = conn.Send("SADD", key+"/"+relation, data2.Bytes())
	_ = conn.Send("HSET", key, "link/"+relation, 1)

	key = execute.Key + "/" + execute.GetDataType(data2.GetDataType()) + utils.ToString(data2.GetId())
	//conn.Watch(key)
	_ = conn.Send("SADD", key+"/"+relation, data1.Bytes())
	_ = conn.Send("HSET", key, "link/"+relation, 1)
}

func (execute *Execute) RemoveLink(conn SafeConn, data1 Data, data2 Data, relation string) {
	key := execute.Key + "/" + execute.GetDataType(data1.GetDataType()) + utils.ToString(data1.GetId()) + "/" + relation
	_, _ = conn.Do("SREM", key, data1.Bytes())

	key = execute.Key + "/" + execute.GetDataType(data2.GetDataType()) + utils.ToString(data2.GetId()) + "/" + relation
	_, _ = conn.Do("SREM", key, data2.Bytes())
}

func (execute *Execute) ClearLink(conn SafeConn, data Data, relation string) {
	rl := execute.GetLink(conn, data, relation)
	if rl == nil || len(rl) == 0 {
		return
	}

	for _, v := range rl {
		key := execute.Key + "/" + execute.GetDataType(v.DataType) + utils.ToString(v.Id) + "/" + relation
		_, _ = conn.Do("SREM", key, 0, data.Bytes())
	}
	_ = conn.Send("DEL", execute.Key+"/"+execute.GetDataType(data.GetDataType())+utils.ToString(data.GetId())+"/"+relation)
	_ = conn.Send("HSET", execute.Key+"/"+execute.GetDataType(data.GetDataType())+utils.ToString(data.GetId()), "link/"+relation, 0)
}
